package com.gmu.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gmu.domain.LoginAdminDetails;
import com.gmu.domain.LoginUserDetails;
import com.gmu.domain.ResResult;
import com.gmu.mapper.TblAdminMapper;
import com.gmu.mapper.TblMenuMapper;
import com.gmu.mapper.TblUserMapper;
import com.gmu.pojo.*;
import com.gmu.pojo.vo.MsgResult;
import com.gmu.pojo.vo.RegisterVo;
import com.gmu.service.LoginService;
import com.gmu.service.TblStudentService;
import com.gmu.service.TblTeacherService;
import com.gmu.service.TblUnitsService;
import com.gmu.utils.JwtUtil;
import com.gmu.utils.Md5Utils;
import com.gmu.utils.RedisCache;
import com.gmu.utils.sendPost;
import lombok.SneakyThrows;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author 木鱼~
 * @version 1.0
 */
@Service
public class LoginServiceImpl extends ServiceImpl<TblUserMapper, TblUser> implements LoginService {
    public static final String username = "18679720725";
    public static final String password = "18679720725";
    public static final String token = "8ff6f7ef";
    public static final String templateid = "16C2835B";

    @Autowired
    private UserDetailsServiceImpl userDetailsServiceImpl;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private AdminDetailServiceImpl adminDetailService;

    @Autowired
    private TblUserMapper tblUserMapper;

    @Resource
    private TblStudentService studentService;

    @Resource
    private TblTeacherService teacherService;

    @Resource
    private TblUnitsService unitsService;

    @Resource
    private RedisTemplate<String,String> redisTemplate;

    @Autowired
    private TblMenuMapper tblMenuMapper;

    @Autowired
    private TblAdminMapper tblAdminMapper;

    @Override
    public ResResult<?> login(String idNumber, String password) {
        LoginUserDetails loginUserDetails = (LoginUserDetails) userDetailsServiceImpl.loadUserByUsername(idNumber);
        if (null==loginUserDetails||!passwordEncoder.matches(password, loginUserDetails.getTblUser().getPassword())){
            return new ResResult<>(404,"用户名或密码错误");
        }
//        String captcha = redisCache.getCacheObject("captcha");
//        if (!captcha.equals(code)){
//            return new ResResult(400,"验证码错误");
//        }
        //每次登录更新security对象
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUserDetails,null,loginUserDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        //如果认证通过，使用userid生成一个jwt jwt存入ResResult返回
        String token = JwtUtil.createJWT(idNumber,"user");//普通用户登录
        HashMap<String, String> map = new HashMap<>();
        map.put("token",token);
        //将token存入redis
        redisCache.setCacheObject("token:"+idNumber,token,7,TimeUnit.DAYS);
        //把完整的用户信息存入redis idNumber作为key
        redisCache.setCacheObject("login:"+idNumber,loginUserDetails,7,TimeUnit.DAYS);
        return new ResResult<>(200,"登录成功",map);
    }


    /**
     * 管理员登录
     * @param username 用户名
     * @param password 密码
     * @param code 验证码
     * @return ResResult
     */
    @Override
    public ResResult<?> loginAdmin(String username, String password, String code) {
        LoginAdminDetails loginAdminDetails = (LoginAdminDetails) adminDetailService.loadUserByUsername(username);
        if (null==loginAdminDetails||!passwordEncoder.matches(password, loginAdminDetails.getTblAdmin().getPassword())){
            return new ResResult<>(404,"用户名或密码错误");
        }
        String captcha = redisCache.getCacheObject("captcha");
        if (StringUtils.isEmpty(captcha)){
            return new ResResult<>(400,"验证码已过期");
        }
        if (!captcha.equals(code)){
            return new ResResult<>(400,"验证码错误");
        }
        //每次登录更新security对象
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginAdminDetails,null,loginAdminDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        //如果认证通过，使用userid生成一个jwt jwt存入ResResult返回
        String token = JwtUtil.createJWT(username,"admin"); //管理员角色登录
        HashMap<String, String> map = new HashMap<>();
        map.put("token",token);
        //将token存入redis
        redisCache.setCacheObject("token:"+username,token,7, TimeUnit.DAYS);
        //将用户信息存入redis
        redisCache.setCacheObject("loginAdmin:"+username,loginAdminDetails,7,TimeUnit.DAYS);
        return new ResResult<>(200,"登录成功",map);
    }

    @Override
    public ResResult<?> logout() {

        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        LoginUserDetails loginUserDetails = (LoginUserDetails) authentication.getPrincipal();
        String idNumber = loginUserDetails.getTblUser().getIdNumber();
        redisCache.deleteObject("login:"+idNumber);//移除redis中该用户的信息
        return new ResResult<>(200,"退出成功");

    }

    @Override
    public ResResult<?> AdminLogout() {

        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        LoginAdminDetails loginAdminDetails = (LoginAdminDetails) authentication.getPrincipal();
        String username = loginAdminDetails.getTblAdmin().getUsername();
        redisCache.deleteObject("loginAdmin:"+username);

        return new ResResult<>(200,"退出成功");
    }

    @Override
    public ResResult<?> adminUpdatePassword(String oldPassword, String newPassword) {

        LoginAdminDetails loginAdminDetails = (LoginAdminDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (Objects.isNull(loginAdminDetails)){
            return new ResResult<>(404,"登录有误");
        }
        TblAdmin tblAdmin = loginAdminDetails.getTblAdmin();
        if (!passwordEncoder.matches(oldPassword,tblAdmin.getPassword())){
            return new ResResult<>(500,"原密码错误");
        }
        tblAdmin.setPassword(passwordEncoder.encode(newPassword));
        if ((tblAdminMapper.updateById(tblAdmin)) < 1){
            return new ResResult<>(500,"修改失败");
        }
        return new ResResult<>(200,"修改成功");

    }

    @Override
    public ResResult<?> adminUpdateInfo(TblAdmin tblAdmin) {

        LoginAdminDetails loginAdminDetails = (LoginAdminDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        if (Objects.isNull(loginAdminDetails)){
            return new ResResult<>(404,"登录有误");
        }
        TblAdmin tblAdmin_ = loginAdminDetails.getTblAdmin();
        tblAdmin_.setUnitsName(tblAdmin.getUnitsName());
        tblAdmin_.setAddress(tblAdmin.getAddress());
        tblAdmin_.setTelephone(tblAdmin.getTelephone());
        if ((tblAdminMapper.updateById(tblAdmin_)) < 1){
            return new ResResult<>(500,"修改失败");
        }
        return new ResResult<>(200,"修改成功");

    }


    //注册用户信息
    @SneakyThrows
    @Override
    public ResResult<?> register(RegisterVo registerVo) {

        //获取注册信息，进行校验
        String idNumber = registerVo.getIdNumber();
        String name = registerVo.getName();
        String telephone = registerVo.getTelephone();
        String password = registerVo.getPassword();
        int roleId = registerVo.getRoleId();
        String code = registerVo.getCode();
        String school = registerVo.getSchool();
        String academy = registerVo.getAcademy();
        String className = registerVo.getClassName();
        String studentNumber = registerVo.getStudentNumber();
        String department = registerVo.getDepartment();
        String teacherNumber = registerVo.getTeacherNumber();
        String sex = registerVo.getSex();
        String major = registerVo.getMajor();
        String grade = registerVo.getGrade();

        //校验参数
        if(StringUtils.isEmpty(idNumber) ||
                StringUtils.isEmpty(name) ||
                StringUtils.isEmpty(telephone) ||
                StringUtils.isEmpty(sex) ||
                StringUtils.isEmpty(password) ||
                StringUtils.isEmpty(roleId) ||
                StringUtils.isEmpty(code) ||
                StringUtils.isEmpty(school) ||
                StringUtils.isEmpty(academy) ||
                StringUtils.isEmpty(major) ||
                (( StringUtils.isEmpty(className) ||
                        StringUtils.isEmpty(studentNumber) ||
                        StringUtils.isEmpty(grade)) &&
                        ( StringUtils.isEmpty(department) ||
                                StringUtils.isEmpty(teacherNumber)))
        ){
//            throw new Exception("信息未填写完整，注册失败");
            return new ResResult<>(500,"信息未填写完整，注册失败");
        }

        //校验验证码
        String mobileCode = redisTemplate.opsForValue().get(telephone);
        if(!code.equals(mobileCode)){
            return new ResResult<>(500,"验证码不正确");
//            throw new Exception("验证码不正确");
        }

        //查询数据库中是否存在相同的身份证号码
        Integer count = baseMapper.selectCount(new
                QueryWrapper<TblUser>().eq("id_number", idNumber));
        if(count > 0) {
//            throw new Exception("该账号已被注册");
            return new ResResult<>(500,"该身份证已被注册");
        }

        //查询数据库中是否存在相同的手机号码
        Integer countMobile = baseMapper.selectCount(new
                QueryWrapper<TblUser>().eq("telephone", telephone));
        if(countMobile > 0) {
//            throw new Exception("该账号已被注册");
            return new ResResult<>(500,"该手机号码已被注册");
        }

        //查询数据库中是否存在相同的学号
        if(roleId==1){
            int countStudentId = studentService.count(new QueryWrapper<TblStudent>().eq("student_number", studentNumber));
            if(countStudentId > 0) {
//            throw new Exception("该账号已被注册");
                return new ResResult<>(500,"该学号已被注册");
            }
        }else if(roleId==2){
            int countTeacherId = teacherService.count(new QueryWrapper<TblTeacher>().eq("teacher_number", teacherNumber));
            if(countTeacherId > 0) {
//            throw new Exception("该账号已被注册");
                return new ResResult<>(500,"该老师工号已被注册");
            }
        }

        Integer unitsId;
        //获取units_id
        QueryWrapper<TblUnits> unitsQueryWrapper = new QueryWrapper<>();
        if(!StringUtils.isEmpty(className)){
            unitsQueryWrapper.eq("name",className);
        }else{
            unitsQueryWrapper.eq("name",department);
        }
        unitsId = unitsService.getOne(unitsQueryWrapper).getUnitsId();

        //数据添加到数据库
        TblUser tblUser = new TblUser();
        tblUser.setName(name);
        tblUser.setIdNumber(idNumber);
        tblUser.setTelephone(telephone);
        tblUser.setPassword(passwordEncoder.encode(password));
        tblUser.setRoleId(roleId);
        tblUser.setDelFlag(0);
        tblUser.setUnitsId(unitsId);
//        BeanUtils.copyProperties(registerVo,tblUser);
        baseMapper.insert(tblUser);
        //根据身份证查询user_id，添加到学生表
        Integer userId = baseMapper.selectOne(new QueryWrapper<TblUser>().eq("id_number", idNumber)).getUserId();
        if(roleId==1){
            TblStudent tblStudent = new TblStudent();
//        tblStudent.setStudentNumber(studentNumber);
//        tblStudent.setTelephone(telephone);
//        tblStudent.setName(name);
//        tblStudent.setIdNumber(idNumber);
//        tblStudent.setSchool(school);
//        tblStudent.setAcademy(academy);
//        tblStudent.setClassName(className);
            BeanUtils.copyProperties(registerVo,tblStudent);
            tblStudent.setUserId(userId);
            tblStudent.setUnitsId(unitsId);
            studentService.save(tblStudent);
        }else if(roleId==2){
            TblTeacher tblTeacher = new TblTeacher();
            BeanUtils.copyProperties(registerVo,tblTeacher);
            tblTeacher.setUserId(userId);
            tblTeacher.setUnitsId(unitsId);
            teacherService.save(tblTeacher);
        }
        return new ResResult<>(200,"注册成功");
    }

    //调用service发送短信的方法
    @Override
    public MsgResult sendMsgPost(String phone, String code) {
        //时间戳
        long timestamp = System.currentTimeMillis();
        //System.out.println(timestamp);
        //url
        String url = "http://www.lokapi.cn/smsUTF8.aspx";
        //签名
        String beforSign = "action=sendtemplate&username="+username+"&password="+ Md5Utils.getMD5String(password)+"&token="+token+"&timestamp="+timestamp;
        //参数串
        String postData = "action=sendtemplate&username="+username+"&password="+ Md5Utils.getMD5String(password)+"&token="+token+"&templateid="+templateid+"&param="+phone+"|"+code+"&rece=json&timestamp="+timestamp+"&sign="+ Md5Utils.getMD5String(beforSign);
        //调用sendPost工具类,发送请求
        String result = sendPost.sendPost(url, postData);
//        //将json结果转为对象，方便判断
//        MsgResult msgResult = JSON.parseObject(result, MsgResult.class);
        MsgResult msgResult = JSON.parseObject(result, MsgResult.class);
        return msgResult;
    }

    @Override
    public ResResult<?> loginByPhone(String phone, String code) {
        String redisCode = redisCache.getCacheObject(phone);
        if (StringUtils.isEmpty(redisCode)){
            return new ResResult<>(500,"手机验证码已过期，请重新登录");
        }
        if (!redisCode.equals(code)){
            return new ResResult<>(500,"手机验证码错误");
        }
        LambdaQueryWrapper<TblUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TblUser::getTelephone,phone);
        TblUser tblUser = tblUserMapper.selectOne(wrapper);
        if (Objects.isNull(tblUser)){
            return new ResResult<>(404,"该用户不存在");
        }
        List<String> perms = tblMenuMapper.getPermsByUserId(tblUser.getUserId());
        LoginUserDetails loginUserDetails = new LoginUserDetails(tblUser,perms);
        //每次登录更新security对象
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUserDetails,null,loginUserDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        //如果认证通过，使用userid生成一个jwt jwt存入ResResult返回
        String idNumber = tblUser.getIdNumber();
        String token = JwtUtil.createJWT(idNumber,"user");//普通用户登录
        HashMap<String, String> map = new HashMap<>();
        map.put("token",token);
        //将token存入redis
        redisCache.setCacheObject("token:"+idNumber,token,7,TimeUnit.DAYS);
        //把完整的用户信息存入redis idNumber作为key
        redisCache.setCacheObject("login:"+idNumber,loginUserDetails,7,TimeUnit.DAYS);
        return new ResResult<>(200,"登录成功",map);
    }



}
